﻿
/*******************************************************************************************
// ©2009 Microsoft Corporation.  This code is provided under the Microsoft Public License.
*******************************************************************************************/

using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using Microsoft.Rtc.Collaboration;
using System.Security.Cryptography.X509Certificates;
using System.Net;
using Microsoft.Rtc.Collaboration.Presence;
using System.Xml;
using System.IO;
using System.Text;
using Microsoft.Rtc.Signaling;
using Microsoft.Rtc.Collaboration.AudioVideo;
using System.Threading;
using System.Configuration;
using ApplicationProvisioning;

namespace ClientBilling
{
    public class BilledCallManager
    {
        #region Static & Instance Variables
        private static BilledCallManager _instance = new BilledCallManager();

        private CollaborationPlatform _collaborationPlatform;
        private ApplicationEndpoint _appEndpoint;
        private AutoResetEvent _callEstablishedWait = new AutoResetEvent(false);

        private string _appName;
        private TrustedApplicationPool _trustedAppPool;
        private TrustedService _trustedService;
        #endregion

        private BilledCallManager()
        {
            // private constructor to enforce singleton
        }

        public static BilledCallManager Instance
        {
            get { return _instance; }
        }

        public BilledCallPlacer GetBilledCallPlacer()
        {
            return new BilledCallPlacer(_appEndpoint);
        }

        #region Startup & Cleanup
        public void Startup()
        {
            // Before doing anything else, we need to create the 
            // CollaborationPlatform and the ApplicationEndPoint.

            // This method is called from Global.asax when the application starts.

            GetTrustedService();

            CreateCollaborationPlatform();
            CreateApplicationEndpoint();

            RegisterForIncomingCalls();

            // Publish presence that shows the endpoint as available.
            PresencePublisher publisher = new PresencePublisher(_appEndpoint);
            publisher.PublishAlwaysAvailable();
        }

        private void GetTrustedService()
        {
            _appName = ConfigUtility.ApplicationUserAgent;

            // Use the ApplicationProvisioning classes to get the platform settings.
            _trustedAppPool = TrustedApplicationPool.GetApplicationPoolForLocalMachine(_appName);

            if (_trustedAppPool == null)
                throw new ArgumentNullException("GetApplicationPoolForLocalMachine()", "Application Pool not found");

            _trustedService = _trustedAppPool.GetTrustedServiceForLocalMachine();

            // Make sure a trusted server entry exists
            if (_trustedService == null)
            {
                throw new ArgumentNullException("GetTrustedServiceForLocalMachine()", "Trusted Service Entry not found");
            }

            // Make sure atleast one contact for the trusted server entry exists
            if (_trustedAppPool.Contacts.Count == 0)
            {
                throw new ArgumentNullException("Contact Object not found for trusted service");
            }
        }

        public void Cleanup()
        {
            // It's important to terminate the endpoint and shut down the CollaborationPlatform when finished.

            // This method is called from Global.asax when the application shuts down.

            _appEndpoint.EndTerminate(_appEndpoint.BeginTerminate(null, null));
            _collaborationPlatform.EndShutdown(_collaborationPlatform.BeginShutdown(null, null));
        }
        #endregion

        #region Initialize CollaborationPlatform
        private void CreateCollaborationPlatform()
        {
            // We need to instantiate the CollaborationPlatform and then start it up, which
            // we're doing here synchronously to keep things simple.

            _collaborationPlatform = new CollaborationPlatform(GetPlatformSettings());
            _collaborationPlatform.EndStartup(_collaborationPlatform.BeginStartup(null, null));
        }

        private ServerPlatformSettings GetPlatformSettings()
        {
            return
                new ServerPlatformSettings(
                    _appName,
                    _trustedService.Fqdn,
                    _trustedService.Port,
                    _trustedService.Gruu,
                    Certificates.GetLocalCertificate()
                );
        }
        #endregion

        #region Initialize ApplicationEndpoint
        private void CreateApplicationEndpoint()
        {
            // We use an ApplicationEndpoint because we want to bridge calls between the lawyer and the clients,
            // rather than functioning as a proxy for a specific user.
            _appEndpoint = new ApplicationEndpoint(
                _collaborationPlatform,
                GetAppEndpointSettings()
            );

            // After instantiating the ApplicationEndpoint, we need to establish it. 
            // We're doing this synchronously for simplicity.
            _appEndpoint.EndEstablish(_appEndpoint.BeginEstablish(null, _appEndpoint));
        }

        private ApplicationEndpointSettings GetAppEndpointSettings()
        {
            // The ApplicationEndpoint constructor takes an ApplicationEndpointSettings object.

            Contact contact = _trustedAppPool.Contacts.First();

            int tlsPort = int.Parse(ConfigUtility.TlsPort);

            ApplicationEndpointSettings settings =
                new ApplicationEndpointSettings(
                    contact.SipUri,
                    contact.HomeServerFqdn,
                    tlsPort);

            settings.UseRegistration = true;

            return settings;
        }
        #endregion

        #region Register For Client Calls
        private void RegisterForIncomingCalls()
        {
            // In order to route incoming calls from clients, we subscribe to all incoming AudioVideoCalls
            // using the RegisterForIncomingCall method of the ApplicationEndpoint.

            IncomingCallRouter router = new IncomingCallRouter(_appEndpoint);
            _appEndpoint.RegisterForIncomingCall<AudioVideoCall>(router.RouteIncomingClientCall);
        }
        #endregion
    }
}
